`timescale 1ns / 1ps
`define ENABLE 1'b0
`define DISABLE 1'b1
`define INIT_COUNTER_VALUE 2400
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    17:49:20 03/10/2010 
// Design Name: 
// Module Name:    RAM_ctrl 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
module RAM_ctrl(
    input clk, reset,
    //to/from main system 
	input mem,//initiates a memory operation
    input rw, //Read or Write (1 - 0)
    input [22:0] address, //Address of the operation to be done
    input [15:0] data_fpga2ram, //Data to be written to RAM(on a write operation)
    output reg ready, //indicates whether the controller is ready to accept a memory operation (if it is ready to receive a new command)
    output [15:0] data_ram2fpga_r, data_ram2fpga_ur,//read data from the RAM chip, registered and unregistered data (registered data remains until next read cycle)
	
	//to/from cellRAM chip
    output [22:0] addr,
	inout [15:0] dio,
	//Control Signals to CellRAM chip
    output we_n,
    output oe_n,    
    output ce_n,
    output ub_n,
    output lb_n,
    output clock_ram,
    output adv_n,
    output cre,
    input o_wait
    );
	

//symbolic state declaration
localparam [2:0]
IDLE	=	3'b000,
READ1	=	3'b100,
READ2	=	3'b101,
WRITE1	=	3'b110,
WRITE2	=	3'b111;

//signal declaration for FSM and datapath
reg [2:0] actual_state, next_state;//actual and next state of the FSM
reg [15:0] data_fpga2ram_reg, data_fpga2ram_next;//actual and next registered data to write
reg [15:0] data_ram2fpga_reg, data_ram2fpga_next;//registered read data from RAM
reg [22:0] addr_reg, addr_next;//registered address for the memory operation

//buffered look-ahead control signals (to achieve clean and glitch free signals at the outputs)
reg we_buf, oe_buf, tri_buf;
reg we_reg, oe_reg, tri_reg;//tri_reg is the registered signal that enables the write data at the inout port (enables the tri-state buffer)

//counter for the initial state
//reg [11:0] counter;/the RAM needs 150uS to initialize. So the controller needs to remain unoperative while the RAM is initializing. The input clock is 16Mhz (period of 62.5 nS), so it needs to remain idle for 150000/62.5 = 2400 clock periods. This is the reason for the counter...

//Control signals unused
reg ce_n_reg, lb_n_reg, ub_n_reg, adv_n_reg;

//body
//FSMD state & data registers
always @ (posedge clk, posedge reset)	
	if(reset)
		begin
			actual_state		<= IDLE;
			addr_reg				<= 0;
			data_fpga2ram_reg	<= 0;
			data_ram2fpga_reg	<= 0;			
			//we_reg				<= `DISABLE;
			oe_reg				<= `DISABLE;
			tri_reg				<= `DISABLE;
			
			ce_n_reg				<= 1'b1;
			lb_n_reg				<= 1'b1;
			ub_n_reg				<= 1'b1;
			adv_n_reg			<= 1'b1;
			
		end
	else
		begin
			actual_state		<= next_state;
			addr_reg 			<= addr_next;
			data_fpga2ram_reg	<= data_fpga2ram_next;
			data_ram2fpga_reg	<= data_ram2fpga_next;			
			//we_reg				<= we_buf;
			oe_reg				<= oe_buf;
			tri_reg				<= tri_buf;
			
			ce_n_reg			<= 1'b0;
			lb_n_reg			<= 1'b0;
			ub_n_reg			<= 1'b0;
			adv_n_reg			<= 1'b0;
			
		end

always @ (negedge clk, posedge reset)
	if(reset) we_reg <= `DISABLE;
	else we_reg <= we_buf;

//FSMD next-state logic
always @*
	begin
		addr_next = addr_reg;
		data_fpga2ram_next = data_fpga2ram_reg;
		data_ram2fpga_next = data_ram2fpga_reg;
		ready = 1'b0;
		case(actual_state)			
			IDLE:
				begin
					if(~mem)
						next_state = IDLE;
					else
						begin
							addr_next = address;
							if(~rw) //write
								begin
									next_state = WRITE1;
									data_fpga2ram_next = data_fpga2ram;
								end
							else //read
								next_state = READ1;					
						end
					ready = 1'b1;
				end
				
			WRITE1:
				next_state = WRITE2;	
				
			WRITE2:
				next_state = IDLE;
			
			READ1:
				next_state = READ2;			
			
			READ2:
				begin
					data_ram2fpga_next = dio;
					next_state = IDLE;
				end
			default:
				next_state = IDLE;
		endcase
	end							

//look-ahead output logic
always @*
	begin
		//we_buf = `DISABLE;
		oe_buf = `DISABLE;
		tri_buf = `DISABLE;
		case(next_state)
			IDLE:
				oe_buf = `DISABLE;
			WRITE1:
				begin
					//we_buf = `ENABLE;
					tri_buf = `ENABLE;
				end	
			WRITE2:
				tri_buf = `ENABLE;	
			READ1:
				oe_buf = `ENABLE;
			READ2:
				oe_buf = `ENABLE;	
		endcase
	end

always @*
	if(actual_state == WRITE1)
		we_buf = `ENABLE;
	else
		we_buf = `DISABLE;

//to main system
assign data_ram2fpga_r = data_ram2fpga_reg;
assign data_ram2fpga_ur = dio;
//to ram
assign we_n = we_reg;
assign oe_n = oe_reg;
assign addr = addr_reg;
//i/o for sram chip
assign ce_n = ce_n_reg;
assign ub_n = ub_n_reg;
assign lb_n = lb_n_reg;
assign clock_ram = 1'b0;
assign adv_n = adv_n_reg;
assign cre = 1'b0;

assign dio = (~tri_reg) ? data_fpga2ram_reg : 16'bz;   

endmodule
